package main

import (
	"os"
	"log"
	"github.com/micro/go-micro"
	pb "learngo/consignment-service/proto/consignment"
	vesselProto "learngo/vessel-service/proto/vessel"
	userPb "learngo/user-service/proto/user"

	"fmt"
	"github.com/micro/go-micro/server"
	"context"
	"github.com/micro/go-micro/metadata"
	"errors"
	"github.com/micro/go-micro/client"
)


const (
	defaultHost = "localhost:27017"
)

func main() {

	// Database host from the environment variables
	host := os.Getenv("DB_HOST")

	if host == "" {
		host = defaultHost
	}

	session,err := CreateSession(host)

	defer session.Close()

	if err != nil {
		log.Panicf("Could not connect to datastore with host %s - %v", host, err)
	}

	srv := micro.NewService(
		// This name must match the package name given in your protobuf definition
		// 注意，Name方法的必须是你在proto文件中定义的package名字
		micro.Name("go.micro.srv.consignment"),
		micro.Version("latest"),
		micro.WrapHandler(AuthWrapper),
	)
	//
	// 我们在这里使用预置的方法生成了一个货船服务的客户端对象
	vesselClient := vesselProto.NewVesselServiceClient("go.micro.srv.vessel", srv.Client())
	//
	//// Init方法会解析命令行flags
	srv.Init()
	//
	pb.RegisterShippingServiceHandler(srv.Server(),&service{session,vesselClient})
	//
	if err := srv.Run();err != nil {
		fmt.Println(err)
	}
}


// AuthWrapper 是一个高阶函数，入参是 ”下一步“ 函数，出参是认证函数
// 在返回的函数内部处理完认证逻辑后，再手动调用 fn() 进行下一步处理
// token 是从 consignment-ci 上下文中取出的，再调用 user-service 将其做验证
// 认证通过则 fn() 继续执行，否则报错
func AuthWrapper(fn server.HandlerFunc) server.HandlerFunc  {

	return func(ctx context.Context, req server.Request, rsp interface{}) error {
		meta,ok := metadata.FromContext(ctx)
		if !ok {
			return errors.New("no auth meta-data found in request")
		}

		token := meta["Token"]

		// 授权验证
		authClient := userPb.NewUserServiceClient("go.micro.srv.user", client.DefaultClient)

		authResp,err := authClient.ValidateToken(context.Background(),&userPb.Token{
			Token: token,
		})

		log.Println("Auth Resp:", authResp)

		if err != nil {
			return err
		}

		return fn(ctx,req,err)
	}

	
}
